#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <limits.h>

#include "file_path.h"

char *ST_to_FP_s(sST *tree) {
    static char path[PATH_MAX+1];

    return ST_to_FP(tree, path, PATH_MAX+1);
}

inline char *ST_to_FP_a(sST *tree) {
    return ST_to_FP(tree, NULL, 0);
}

char *ST_to_FP(sST *tree, char *path, unsigned int pathsize) { // returns a relative path
    if(!tree) return NULL;

    int method=0;   // external fixed size allocated buffer

    if(!path) {
        if(pathsize) {
            path=(char *)malloc(pathsize);
            if(!path) return NULL;

            method=1;   // internal fixed size allocated buffer
        }
        else
            method=2;   // internal floating size allocated buffer
    }
    else if(pathsize<=1) return NULL;

    unsigned int allocd=0, used=0, num, slen;
    char **pl=NULL;
    int i;

    // on crée la liste descendante des noms de fichiers
    while(tree) {
        if(used>=allocd) {
            allocd+=4;
            pl=(char **)realloc(pl, allocd*sizeof(char *));
            if(!pl) return NULL;
        }

        pl[used++]=tree->name;

        tree=tree->parent;
    }

    if(used!=allocd)    // on n'alloue que la taille utilisée
        pl=(char **)realloc(pl, used*sizeof(char *));

    num=used;

    // on la traverse en partant de la fin pour recréer le chemin
    used=0;
    allocd=pathsize-1;
    for(i=(int)num-1; i>=0; i--) {
        slen=strlen(pl[i]);

        if(used+slen+(i?1:0)>allocd) {  // won't fit in allocated space
            switch(method) {
            case 1:
                free(path);
            case 0:
                free(pl);
                return NULL;
            case 2:
                allocd+=slen*4;
                path=(char *)realloc(path, allocd+1);
                if(!path) {
                    free(pl);
                    return NULL;
                }
            default:
                break;
            }
        }

        strcpy(path+used, pl[i]);
        used+=slen;

        if(i>0) {   // on ajoute le séparateur tant que ce n'est pas le dernier
            path[used++]='/';
            path[used]='\0';
        }
    }

    free(pl);
    return path;
}

sST *FP_to_ST(sST *tree, char *path /* relative path */) {
    if(!tree || !path) return NULL;

    char *curf;
    sST *tmp;
    path=strdup(path);

    curf=strtok (path, "/");
    while(curf) {
        tmp=tree;
        while(tmp) {
            if(!strcmp(curf, tmp->name)) break;

            tmp=tmp->next;
        }

        if(!tmp) break;

        tree=tmp->child;

        curf=strtok(NULL, "/");
    }

    free(path);
    return tmp;
}

int FP_is_absolute(char *fp) {
    if(!fp) return 0;

#if 1
    // TODO : improve check

    if(fp[0]=='/') return 1;

    return 0;
#endif
}

char *FP_to_absolute_s(char *src) {
    static char path[PATH_MAX+1];

    return FP_to_absolute(src, path, PATH_MAX+1);
}

inline char *FP_to_absolute_a(char *src) {
    return FP_to_absolute(src, NULL, 0);
}

char *FP_to_absolute(char *src, char *dst, unsigned int dstsize) {
    if(!src) return NULL;

    int method=0;
    unsigned int srclen=strlen(src);

    if(!dst) {
        if(dstsize) {
            dst=(char *)malloc(dstsize);
            if(!dst) return NULL;

            method=1;
        }
        else
            method=2;
    }
    else if(dstsize<=1) return NULL;

    if(FP_is_absolute(src)) {
        switch(method) {
        case 0:
        case 1:
            if(srclen>dstsize-1) {
                if(method==1) free(dst);
                return NULL;
            }
            strcpy(dst, src);
        case 2:
            dst=strdup(src);
        }
    }
    else {
        switch(method) {
        case 0:
        case 1:
            if(srclen>dstsize-1) {
                if(method==1) free(dst);
                return NULL;
            }
            if(!getcwd(dst, dstsize-srclen)) {
                if(method==1) free(dst);
                return NULL;
            }
        case 2:
            {
                char wd[PATH_MAX+1];
                if(!getcwd(wd, PATH_MAX+1)) return NULL;

                dst=(char *)malloc(strlen(wd)+1+srclen+1);
                if(!dst) return NULL;

                strcpy(dst, wd);
            }
        }
        strcat(dst, "/");
        strcat(dst, src);
    }

    return dst;
}

